#pragma once

/* Let's see whether hiding this away somewhere where the compiler can't
   see it will cure it of its silly urge to mis-optimize the comparison */
extern int pissoff_value;

static __forceinline void events_schedule()
{
    int i;

    uint mintime = ~0L;
    for (i = 0; i < ev_max; i++)
    {
        if (eventtab[i].active)
        {
            uint eventtime = eventtab[i].evtime - currcycle;
            if (Logging::EVENT_DEBUG)
            {
                if (eventtime == 0)
                {
                    Logger::Write(L"event %d bug\n", i);
                }
            }
            if (eventtime < mintime)
                mintime = eventtime;
        }
    }
    nextevent = currcycle + mintime;
}

extern int pissoff;

static __forceinline void cycles_do_special()
{
    #ifdef JIT
    if (g_curr_conf.jit_cache_size)
    {
        if (pissoff >= 0)
            pissoff = -1;
    }
    else
    #endif
    {
        pissoff = 0;
    }
}

static __forceinline void do_extra_cycles(uint cycles_to_add)
{
    pissoff -= cycles_to_add;
}

static __forceinline uint get_cycles()
{
    return currcycle;
}

static __forceinline void set_cycles(uint x)
{
    currcycle = x;
    eventtab[ev_hsync].oldcycles = x;
    if (Logging::EVENT_DEBUG)
    {
        if (currcycle & (CYCLE_UNIT - 1))
            Logger::Write(L"%x\n", currcycle);
    }
}

static __forceinline void do_cycles_slow(uint cycles_to_add)
{
    if ((pissoff -= cycles_to_add) >= 0)
        return;

    cycles_to_add = -pissoff;
    pissoff = 0;

    if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add)
    {
        int rpt = read_processor_time();
        int v = rpt - vsyncmintime;
        if (v > (int)syncbase || v < -((int)syncbase))
            vsyncmintime = rpt;
        if (v < 0)
        {
            pissoff = pissoff_value * CYCLE_UNIT;
            return;
        }
    }
    while ((nextevent - currcycle) <= cycles_to_add)
    {
        int i;
        cycles_to_add -= (nextevent - currcycle);
        currcycle = nextevent;

        for (i = 0; i < ev_max; i++)
        {
            if (eventtab[i].active && eventtab[i].evtime == currcycle)
            {
                (*eventtab[i].handler)();
            }
        }
        events_schedule();
    }
    currcycle += cycles_to_add;
    if (Logging::EVENT_DEBUG)
    {
        if (currcycle & (CYCLE_UNIT - 1))
            Logger::Write(L"%x\n", currcycle);
    }
}

#define do_cycles do_cycles_slow
#define countdown pissoff